package com.noovo.comport.server;

import android.app.Service;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Intent;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import java.util.HashMap;

import com.noovo.comport.serial.MyFunc;
import com.noovo.comport.serial.SerialBean;

public class ComService extends Service {
	private static ComService service;
	private final Uri URI_IN = Uri.parse("content://com.noovo.comport.setting/port_in");
	private final static Uri URI_OUT_RECEIVE = Uri.parse("content://com.noovo.comport.setting/port_out/receive");
	private static HashMap<Integer, ComHandler> MAP_HADNLER;
	private ComObserver mComObserver;
	private static ContentResolver resolver;

	private final class ComObserver extends ContentObserver {

		public ComObserver(Handler handler) {
			super(handler);
		}

		@Override
		public void onChange(boolean selfChange, Uri uri) {
			comInChange(uri);
		}
	}

	private static Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case ComInfo.HANDLER_SERVICE_RECEIVE: {
				ContentValues values = (ContentValues) msg.obj;
				int port = values.getAsInteger(ComInfo.DB_ITEM_PORT);
				String name = values.getAsString(ComInfo.DB_ITEM_NAME);
				byte[] m = values.getAsByteArray(ComInfo.DB_ITEM_RECEIVE);
				int store_id = values.getAsInteger(ComInfo.DB_ITEM_RECEIVE_ID);
				if (ComInfo.DEBUG_ON)
					Log.d(ComInfo.TAG, "COM OUT RECEIVE://port=" + port + " portName=" + name + " store-id=" + store_id
							+ " msg-length=" + m.length + " " + MyFunc.ByteArrToHex(m));
				values.put(ComInfo.DB_ITEM_RECEIVE + "_" + store_id, m);
				values.remove(ComInfo.DB_ITEM_RECEIVE);
				values.remove(ComInfo.DB_ITEM_RECEIVE_ID);
				Uri uri = ContentUris.withAppendedId(URI_OUT_RECEIVE, port);
				uri = ContentUris.withAppendedId(uri, store_id);
				resolver.update(uri, values, null, null);
			}
				break;
			case ComInfo.HANDLER_SERVICE_ERROR: {
				int port = (Integer) msg.obj;
				MAP_HADNLER.get(port).initAndOpenSerial();
			}
				break;
			case ComInfo.HANDLER_SERVICE_COM_DATA_RECEIVE: {
				SerialBean bean = (SerialBean) msg.obj;
				MAP_HADNLER.get(bean.getPort()).onDataReceive(bean.getBuffer());
			}
				break;
			default:
				MAP_HADNLER.get(msg.what).finishDataReceive();
				break;
			}
		}
	};

	@Override
	public IBinder onBind(Intent intent) {
		return new MyBinder();
	}

	public class MyBinder extends Binder {
		public ComService getService() {
			if (service == null)
				service = new ComService();
			return service;
		}
	}

	@Override
	public void onCreate() {
		super.onCreate();
		Log.d(ComInfo.TAG, "ComServer onCreate");
		resolver = getContentResolver();
		MAP_HADNLER = new HashMap<Integer, ComHandler>();
		for (int port = 1; port < 5; port++) {
			ComHandler comHandler = new ComHandler(port, mHandler);
			MAP_HADNLER.put(port, comHandler);
		}
		mComObserver = new ComObserver(new Handler());
		resolver.registerContentObserver(URI_IN, true, mComObserver);
	}

	@Override
	public void onDestroy() {
		resolver.unregisterContentObserver(mComObserver);
		for (int port = 1; port < 5; port++) {
			MAP_HADNLER.get(port).onClose();
		}
		mHandler.removeCallbacksAndMessages(null);
		super.onDestroy();
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		flags = START_STICKY;
		return super.onStartCommand(intent, flags, startId);
	}

	private void comInChange(Uri uri) {
		int type = ComInfo.uriMatcher.match(uri);
		int port = Integer.parseInt(uri.getPathSegments().get(2));
		ComHandler comHandler = MAP_HADNLER.get(port);
		switch (type) {
		case ComInfo.TYPE_PORT_IN_SET: {
			String[] projection = { ComInfo.DB_ITEM_NAME, ComInfo.DB_ITEM_RATE, ComInfo.DB_ITEM_DATABITS,
					ComInfo.DB_ITEM_STOPBITS, ComInfo.DB_ITEM_PARITY };
			Cursor cursor = resolver.query(uri, projection, null, null, null);
			if (cursor != null && cursor.moveToFirst()) {
				String name = cursor.getString(cursor.getColumnIndex(ComInfo.DB_ITEM_NAME));
				int rate = cursor.getInt(cursor.getColumnIndex(ComInfo.DB_ITEM_RATE));
				int databits = cursor.getInt(cursor.getColumnIndex(ComInfo.DB_ITEM_DATABITS));
				int stopbits = cursor.getInt(cursor.getColumnIndex(ComInfo.DB_ITEM_STOPBITS));
				char parity = cursor.getString(cursor.getColumnIndex(ComInfo.DB_ITEM_PARITY)).charAt(0);
				cursor.close();
				Log.d(ComInfo.TAG, "COM IN SET://port=" + port + " portName=" + name + " rate=" + rate + " databits="
						+ databits + " stopbits=" + stopbits + " parity=" + parity);
				comHandler.setName(name);
				comHandler.onOpen(rate, databits, stopbits, parity);
			}
			break;
		}
		case ComInfo.TYPE_PORT_IN_SEND: {
			String[] projection = { ComInfo.DB_ITEM_NAME, ComInfo.DB_ITEM_SEND, ComInfo.DB_ITEM_LOOP,
					ComInfo.DB_ITEM_DELAY, ComInfo.DB_ITEM_MSG };
			Cursor cursor = resolver.query(uri, projection, null, null, null);
			if (cursor != null && cursor.moveToFirst()) {
				boolean send = Boolean.parseBoolean(cursor.getString(cursor.getColumnIndex(ComInfo.DB_ITEM_SEND)));
				if (send) {
					String name = cursor.getString(cursor.getColumnIndex(ComInfo.DB_ITEM_NAME));
					byte[] msg = cursor.getBlob(cursor.getColumnIndex(ComInfo.DB_ITEM_MSG));
					boolean loop = Boolean.parseBoolean(cursor.getString(cursor.getColumnIndex(ComInfo.DB_ITEM_LOOP)));
					int delay = cursor.getInt(cursor.getColumnIndex(ComInfo.DB_ITEM_DELAY));
					Log.d(ComInfo.TAG, "COM IN SEND://port=" + port + " msg-length=" + msg.length + " loop=" + loop
							+ " delay=" + delay + " " + MyFunc.ByteArrToHex(msg));
					comHandler.onSendMessage(msg, loop, delay);
				} else {
					Log.d(ComInfo.TAG, "COM IN SEND://port=" + port + " send close");
					comHandler.onStopMessage();
				}
				cursor.close();
			}
			break;
		}
		}

	}
}
